home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Resources / Chat & Communication / Digsby build 37 / digsby_setup.exe / lib / pyxmpp / cache.pyo (.txt) < prev    next >
Python Compiled Bytecode  |  2008-10-13  |  11KB  |  450 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyo (Python 2.5)
  3.  
  4. __revision__ = '$Id: cache.py 647 2006-08-26 18:27:39Z jajcus $'
  5. __docformat__ = 'restructuredtext en'
  6. import threading
  7. from datetime import datetime, timedelta
  8. _state_values = {
  9.     'new': 0,
  10.     'fresh': 1,
  11.     'old': 2,
  12.     'stale': 3,
  13.     'purged': 4 }
  14.  
  15. class CacheItem(object):
  16.     __slots__ = [
  17.         'value',
  18.         'address',
  19.         'state',
  20.         'timestamp',
  21.         'freshness_time',
  22.         'expire_time',
  23.         'purge_time',
  24.         'state_value',
  25.         '_lock']
  26.     
  27.     def __init__(self, address, value, freshness_period, expiration_period, purge_period, state = 'new'):
  28.         if freshness_period > expiration_period:
  29.             raise ValueError, 'freshness_period greater then expiration_period'
  30.         
  31.         if expiration_period > purge_period:
  32.             raise ValueError, 'expiration_period greater then purge_period'
  33.         
  34.         self.address = address
  35.         self.value = value
  36.         now = datetime.utcnow()
  37.         self.timestamp = now
  38.         self.freshness_time = now + freshness_period
  39.         self.expire_time = now + expiration_period
  40.         if purge_period:
  41.             self.purge_time = now + purge_period
  42.         else:
  43.             self.purge_time = datetime.max
  44.         self.state = state
  45.         self.state_value = _state_values[state]
  46.         self._lock = threading.RLock()
  47.  
  48.     
  49.     def update_state(self):
  50.         self._lock.acquire()
  51.         
  52.         try:
  53.             now = datetime.utcnow()
  54.             if self.state == 'new':
  55.                 self.state = 'fresh'
  56.             
  57.             if self.state == 'fresh':
  58.                 if now > self.freshness_time:
  59.                     self.state = 'old'
  60.                 
  61.             
  62.             if self.state == 'old':
  63.                 if now > self.expire_time:
  64.                     self.state = 'stale'
  65.                 
  66.             
  67.             if self.state == 'stale':
  68.                 if now > self.purge_time:
  69.                     self.state = 'purged'
  70.                 
  71.             
  72.             self.state_value = _state_values[self.state]
  73.             return self.state
  74.         finally:
  75.             self._lock.release()
  76.  
  77.  
  78.     
  79.     def __cmp__(self, other):
  80.         
  81.         try:
  82.             return cmp((-(self.state_value), self.timestamp, id(self)), (-(other.state_value), other.timestamp, id(other)))
  83.         except AttributeError:
  84.             return cmp(id(self), id(other))
  85.  
  86.  
  87.  
  88. _hour = timedelta(hours = 1)
  89.  
  90. class CacheFetcher:
  91.     
  92.     def __init__(self, cache, address, item_freshness_period, item_expiration_period, item_purge_period, object_handler, error_handler, timeout_handler, timeout_period, backup_state = None):
  93.         self.cache = cache
  94.         self.address = address
  95.         self._item_freshness_period = item_freshness_period
  96.         self._item_expiration_period = item_expiration_period
  97.         self._item_purge_period = item_purge_period
  98.         self._object_handler = object_handler
  99.         self._error_handler = error_handler
  100.         self._timeout_handler = timeout_handler
  101.         if timeout_period:
  102.             self.timeout_time = datetime.utcnow() + timeout_period
  103.         else:
  104.             self.timeout_time = datetime.max
  105.         self._backup_state = backup_state
  106.         self.active = True
  107.  
  108.     
  109.     def _deactivate(self):
  110.         self.cache.remove_fetcher(self)
  111.         if self.active:
  112.             self._deactivated()
  113.         
  114.  
  115.     
  116.     def _deactivated(self):
  117.         self.active = False
  118.  
  119.     
  120.     def fetch(self):
  121.         raise RuntimeError, 'Pure virtual method called'
  122.  
  123.     
  124.     def got_it(self, value, state = 'new'):
  125.         if not self.active:
  126.             return None
  127.         
  128.         item = CacheItem(self.address, value, self._item_freshness_period, self._item_expiration_period, self._item_purge_period, state)
  129.         self._object_handler(item.address, item.value, item.state)
  130.         self.cache.add_item(item)
  131.         self._deactivate()
  132.  
  133.     
  134.     def error(self, error_data):
  135.         if not self.active:
  136.             return None
  137.         
  138.         if not self._try_backup_item():
  139.             self._error_handler(self.address, error_data)
  140.         
  141.         self.cache.invalidate_object(self.address)
  142.         self._deactivate()
  143.  
  144.     
  145.     def timeout(self):
  146.         if not self.active:
  147.             return None
  148.         
  149.         if not self._try_backup_item():
  150.             if self._timeout_handler:
  151.                 self._timeout_handler(self.address)
  152.             else:
  153.                 self._error_handler(self.address, None)
  154.         
  155.         self.cache.invalidate_object(self.address)
  156.         self._deactivate()
  157.  
  158.     
  159.     def _try_backup_item(self):
  160.         if not self._backup_state:
  161.             return False
  162.         
  163.         item = self.cache.get_item(self.address, self._backup_state)
  164.         if item:
  165.             self._object_handler(item.address, item.value, item.state)
  166.             return True
  167.         else:
  168.             False
  169.  
  170.  
  171.  
  172. class Cache:
  173.     
  174.     def __init__(self, max_items, default_freshness_period = _hour, default_expiration_period = 12 * _hour, default_purge_period = 24 * _hour):
  175.         self.default_freshness_period = default_freshness_period
  176.         self.default_expiration_period = default_expiration_period
  177.         self.default_purge_period = default_purge_period
  178.         self.max_items = max_items
  179.         self._items = { }
  180.         self._items_list = []
  181.         self._fetcher = None
  182.         self._active_fetchers = []
  183.         self._purged = 0
  184.         self._lock = threading.RLock()
  185.  
  186.     
  187.     def request_object(self, address, state, object_handler, error_handler = None, timeout_handler = None, backup_state = None, timeout = timedelta(minutes = 60), freshness_period = None, expiration_period = None, purge_period = None):
  188.         self._lock.acquire()
  189.         
  190.         try:
  191.             if state == 'stale':
  192.                 state = 'purged'
  193.             
  194.             item = self.get_item(address, state)
  195.             if item:
  196.                 object_handler(item.address, item.value, item.state)
  197.                 return None
  198.             
  199.             if not self._fetcher:
  200.                 raise TypeError, 'No cache fetcher defined'
  201.             
  202.             if not error_handler:
  203.                 
  204.                 def default_error_handler(address, _unused):
  205.                     return object_handler(address, None, 'error')
  206.  
  207.                 error_handler = default_error_handler
  208.             
  209.             if not timeout_handler:
  210.                 
  211.                 def default_timeout_handler(address):
  212.                     return error_handler(address, None)
  213.  
  214.                 timeout_handler = default_timeout_handler
  215.             
  216.             if freshness_period is None:
  217.                 freshness_period = self.default_freshness_period
  218.             
  219.             if expiration_period is None:
  220.                 expiration_period = self.default_expiration_period
  221.             
  222.             if purge_period is None:
  223.                 purge_period = self.default_purge_period
  224.             
  225.             fetcher = self._fetcher(self, address, freshness_period, expiration_period, purge_period, object_handler, error_handler, timeout_handler, timeout, backup_state)
  226.             fetcher.fetch()
  227.             self._active_fetchers.append((fetcher.timeout_time, fetcher))
  228.             self._active_fetchers.sort()
  229.         finally:
  230.             self._lock.release()
  231.  
  232.  
  233.     
  234.     def invalidate_object(self, address, state = 'stale'):
  235.         self._lock.acquire()
  236.         
  237.         try:
  238.             item = self.get_item(address)
  239.             if item and item.state_value < _state_values[state]:
  240.                 item.state = state
  241.                 item.update_state()
  242.                 self._items_list.sort()
  243.         finally:
  244.             self._lock.release()
  245.  
  246.  
  247.     
  248.     def add_item(self, item):
  249.         self._lock.acquire()
  250.         
  251.         try:
  252.             state = item.update_state()
  253.             if state != 'purged':
  254.                 if len(self._items_list) >= self.max_items:
  255.                     self.purge_items()
  256.                 
  257.                 self._items[item.address] = item
  258.                 self._items_list.append(item)
  259.                 self._items_list.sort()
  260.             
  261.             return item.state
  262.         finally:
  263.             self._lock.release()
  264.  
  265.  
  266.     
  267.     def get_item(self, address, state = 'fresh'):
  268.         self._lock.acquire()
  269.         
  270.         try:
  271.             item = self._items.get(address)
  272.             if not item:
  273.                 return None
  274.             
  275.             self.update_item(item)
  276.             if _state_values[state] >= item.state_value:
  277.                 return item
  278.             
  279.             return None
  280.         finally:
  281.             self._lock.release()
  282.  
  283.  
  284.     
  285.     def update_item(self, item):
  286.         self._lock.acquire()
  287.         
  288.         try:
  289.             state = item.update_state()
  290.             self._items_list.sort()
  291.             if item.state == 'purged':
  292.                 self._purged += 1
  293.                 if self._purged > 0.25 * self.max_items:
  294.                     self.purge_items()
  295.                 
  296.             
  297.             return state
  298.         finally:
  299.             self._lock.release()
  300.  
  301.  
  302.     
  303.     def num_items(self):
  304.         return len(self._items_list)
  305.  
  306.     
  307.     def purge_items(self):
  308.         self._lock.acquire()
  309.         
  310.         try:
  311.             il = self._items_list
  312.             num_items = len(il)
  313.             need_remove = num_items - int(0.75 * self.max_items)
  314.             for _unused in range(need_remove):
  315.                 item = il.pop(0)
  316.                 
  317.                 try:
  318.                     del self._items[item.address]
  319.                 continue
  320.                 except KeyError:
  321.                     continue
  322.                 
  323.  
  324.             
  325.             while il and il[0].update_state() == 'purged':
  326.                 item = il.pop(0)
  327.                 
  328.                 try:
  329.                     del self._items[item.address]
  330.                 continue
  331.                 except KeyError:
  332.                     None<EXCEPTION MATCH>KeyError
  333.                     None<EXCEPTION MATCH>KeyError
  334.                     continue
  335.                 
  336.  
  337.                 None<EXCEPTION MATCH>KeyError<EXCEPTION MATCH>KeyError
  338.         finally:
  339.             self._lock.release()
  340.  
  341.  
  342.     
  343.     def tick(self):
  344.         self._lock.acquire()
  345.         
  346.         try:
  347.             now = datetime.utcnow()
  348.             for t, f in list(self._active_fetchers):
  349.                 if t > now:
  350.                     break
  351.                 
  352.                 f.timeout()
  353.             
  354.             self.purge_items()
  355.         finally:
  356.             self._lock.release()
  357.  
  358.  
  359.     
  360.     def remove_fetcher(self, fetcher):
  361.         self._lock.acquire()
  362.         
  363.         try:
  364.             for t, f in list(self._active_fetchers):
  365.                 if f is fetcher:
  366.                     self._active_fetchers.remove((t, f))
  367.                     f._deactivated()
  368.                     return None
  369.                     continue
  370.         finally:
  371.             self._lock.release()
  372.  
  373.  
  374.     
  375.     def set_fetcher(self, fetcher_class):
  376.         self._lock.acquire()
  377.         
  378.         try:
  379.             self._fetcher = fetcher_class
  380.         finally:
  381.             self._lock.release()
  382.  
  383.  
  384.  
  385.  
  386. class CacheSuite:
  387.     
  388.     def __init__(self, max_items, default_freshness_period = _hour, default_expiration_period = 12 * _hour, default_purge_period = 24 * _hour):
  389.         self.default_freshness_period = default_freshness_period
  390.         self.default_expiration_period = default_expiration_period
  391.         self.default_purge_period = default_purge_period
  392.         self.max_items = max_items
  393.         self._caches = { }
  394.         self._lock = threading.RLock()
  395.  
  396.     
  397.     def request_object(self, object_class, address, state, object_handler, error_handler = None, timeout_handler = None, backup_state = None, timeout = None, freshness_period = None, expiration_period = None, purge_period = None):
  398.         self._lock.acquire()
  399.         
  400.         try:
  401.             if object_class not in self._caches:
  402.                 raise TypeError, 'No cache for %r' % (object_class,)
  403.             
  404.             self._caches[object_class].request_object(address, state, object_handler, error_handler, timeout_handler, backup_state, timeout, freshness_period, expiration_period, purge_period)
  405.         finally:
  406.             self._lock.release()
  407.  
  408.  
  409.     
  410.     def tick(self):
  411.         self._lock.acquire()
  412.         
  413.         try:
  414.             for cache in self._caches.values():
  415.                 cache.tick()
  416.         finally:
  417.             self._lock.release()
  418.  
  419.  
  420.     
  421.     def register_fetcher(self, object_class, fetcher_class):
  422.         self._lock.acquire()
  423.         
  424.         try:
  425.             cache = self._caches.get(object_class)
  426.             if not cache:
  427.                 cache = Cache(self.max_items, self.default_freshness_period, self.default_expiration_period, self.default_purge_period)
  428.                 self._caches[object_class] = cache
  429.             
  430.             cache.set_fetcher(fetcher_class)
  431.         finally:
  432.             self._lock.release()
  433.  
  434.  
  435.     
  436.     def unregister_fetcher(self, object_class):
  437.         self._lock.acquire()
  438.         
  439.         try:
  440.             cache = self._caches.get(object_class)
  441.             if not cache:
  442.                 return None
  443.             
  444.             cache.set_fetcher(None)
  445.         finally:
  446.             self._lock.release()
  447.  
  448.  
  449.  
  450.